﻿using Sidvall.Serialization;
using System.Threading;
using System.Threading.Tasks;

namespace Sidvall.IO
{
    public static class StorageGroupManager
    {
        #region Public Members

        #region CopyFileAsync

        public static async Task CopyFileAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager, string destinationPath)
        {
            await CopyFileAsync(sourceStorageManager, sourcePath, destinationStorageManager, destinationPath, null, CancellationToken.None).ConfigureAwait(false);
        }
        public static async Task CopyFileAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager, string destinationPath,
            System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            await CopyFileAsync(sourceStorageManager, sourcePath, destinationStorageManager, destinationPath, null, progress, cancellationToken).ConfigureAwait(false);
        }
        public static async Task CopyFileAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager, string destinationPath,
            int? bufferSize, System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            if (bufferSize == null)
            {
                bufferSize = destinationStorageManager.Storage.DefaultBufferSize;
                if (sourceStorageManager.Storage.DefaultBufferSize > bufferSize)
                    bufferSize = sourceStorageManager.Storage.DefaultBufferSize;
            }
            using (var stream = await sourceStorageManager.OpenFileAsync(sourcePath, Sidvall.IO.FileMode.Open, Sidvall.IO.FileAccess.Read, cancellationToken).ConfigureAwait(false))
            {
                await CopyStreamAsync(stream, destinationStorageManager, destinationPath, bufferSize, progress, cancellationToken).ConfigureAwait(false);
            }
        }
        public static async Task CopyFileAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager, string destinationPath,
            BufferMode bufferMode)
        {
            await CopyFileAsync(sourceStorageManager, sourcePath, destinationStorageManager, destinationPath, bufferMode, null, CancellationToken.None).ConfigureAwait(false);
        }
        public static async Task CopyFileAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager, string destinationPath,
            BufferMode bufferMode, System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            switch (bufferMode)
            {
                case BufferMode.StreamLength:
                    using (var stream = await sourceStorageManager.OpenFileAsync(sourcePath, Sidvall.IO.FileMode.Open, Sidvall.IO.FileAccess.Read, cancellationToken).ConfigureAwait(false))
                    {
                        await CopyStreamAsync(stream, destinationStorageManager, destinationPath, bufferMode, progress, cancellationToken).ConfigureAwait(false);
                    }
                    break;
                default:
                    await CopyFileAsync(sourceStorageManager, sourcePath, destinationStorageManager, destinationPath, null, progress, cancellationToken).ConfigureAwait(false);
                    break;
            }
        }

        #endregion
        #region CopyFileToTemporaryPathAsync

        public static async Task<string> CopyFileToTemporaryPathAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager)
        {
            return await CopyFileToTemporaryPathAsync(sourceStorageManager, sourcePath, destinationStorageManager, null, CancellationToken.None).ConfigureAwait(false);
        }
        public static async Task<string> CopyFileToTemporaryPathAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager,
            System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            var extension = System.IO.Path.GetExtension(sourcePath);
            var destinationPath = destinationStorageManager.GetTemporaryFilePath(extension);
            await CopyFileAsync(sourceStorageManager, sourcePath, destinationStorageManager, destinationPath, progress, cancellationToken).ConfigureAwait(false);
            return destinationPath;
        }
        public static async Task<string> CopyFileToTemporaryPathAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager,
            BufferMode bufferMode)
        {
            return await CopyFileToTemporaryPathAsync(sourceStorageManager, sourcePath, destinationStorageManager, bufferMode, null, CancellationToken.None).ConfigureAwait(false);
        }
        public static async Task<string> CopyFileToTemporaryPathAsync(StorageManager sourceStorageManager, string sourcePath, StorageManager destinationStorageManager,
            BufferMode bufferMode, System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            var extension = System.IO.Path.GetExtension(sourcePath);
            var destinationPath = destinationStorageManager.GetTemporaryFilePath(extension);
            await CopyFileAsync(sourceStorageManager, sourcePath, destinationStorageManager, destinationPath, bufferMode, progress, cancellationToken).ConfigureAwait(false);
            return destinationPath;
        }

        #endregion
        #region CopyStreamAsync

        public static async Task CopyStreamAsync(System.IO.Stream sourceStream, StorageManager destinationStorageManager, string destinationPath,
            int? bufferSize)
        {
            await CopyStreamAsync(sourceStream, destinationStorageManager, destinationPath, bufferSize, null, CancellationToken.None).ConfigureAwait(false);
        }
        public static async Task CopyStreamAsync(System.IO.Stream sourceStream, StorageManager destinationStorageManager, string destinationPath,
            int? bufferSize, System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            if (bufferSize == null)
                bufferSize = destinationStorageManager.Storage.DefaultBufferSize;
            await destinationStorageManager.WriteStreamAsync(destinationPath, sourceStream, bufferSize.Value, progress, cancellationToken).ConfigureAwait(false);
        }
        public static async Task CopyStreamAsync(System.IO.Stream sourceStream, StorageManager destinationStorageManager, string destinationPath,
            BufferMode bufferMode)
        {
            await CopyStreamAsync(sourceStream, destinationStorageManager, destinationPath, bufferMode, null, CancellationToken.None).ConfigureAwait(false);
        }
        public static async Task CopyStreamAsync(System.IO.Stream sourceStream, StorageManager destinationStorageManager, string destinationPath,
            BufferMode bufferMode, System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            int bufferSize;

            switch (bufferMode)
            {
                case BufferMode.StreamLength:
                    bufferSize = (int)sourceStream.Length;
                    break;
                default:
                    bufferSize = destinationStorageManager.Storage.DefaultBufferSize;
                    break;
            }
            await destinationStorageManager.WriteStreamAsync(destinationPath, sourceStream, bufferSize, progress, cancellationToken).ConfigureAwait(false);
        }

        #endregion
        #region CopyStreamToTemporaryPathAsync

        public static async Task<string> CopyStreamToTemporaryPathAsync(System.IO.Stream sourceStream, string extension, StorageManager destinationStorageManager)
        {
            return await CopyStreamToTemporaryPathAsync(sourceStream, extension, destinationStorageManager, null, CancellationToken.None).ConfigureAwait(false);
        }
        public static async Task<string> CopyStreamToTemporaryPathAsync(System.IO.Stream sourceStream, string extension, StorageManager destinationStorageManager,
            System.IProgress<FileProgress> progress, CancellationToken cancellationToken)
        {
            var destinationPath = destinationStorageManager.GetTemporaryFilePath(extension);
            await CopyStreamAsync(sourceStream, destinationStorageManager, destinationPath, null, progress, cancellationToken).ConfigureAwait(false);
            return destinationPath;
        }

        #endregion
        #region CreateStorageManagerAsync

        public static async Task<Sidvall.IO.StorageManager> CreateStorageManagerAsync(string factoryTypeName, string context)
        {
            var item = new Sidvall.Reflection.InstanceItem()
            {
                FactoryTypeName = factoryTypeName,
                Context = context,
            };
            var storage = await Sidvall.SystemContext.Current.CodeManager.CreateInstanceAsync<IStorage>(item).ConfigureAwait(false);
            if (storage != null)
                return new Sidvall.IO.StorageManager(storage);
            return null;
        }

        #endregion
        #region GetFileSystemEntryName

        public static string GetFileSystemEntryName(string path, string folderDelimiter)
        {
            if (string.IsNullOrWhiteSpace(path))
                return string.Empty;
            if (string.IsNullOrWhiteSpace(folderDelimiter))
                return path;
            int pos = path.LastIndexOf(folderDelimiter, System.StringComparison.OrdinalIgnoreCase);
            if (pos >= 0)
                return path.Substring(pos + folderDelimiter.Length, path.Length - pos - folderDelimiter.Length);
            return path;
        }

        #endregion
        #region GetPathWithoutRoot

        public static string GetPathWithoutRoot(string path, string rootPath, string folderDelimiter)
        {
            if (string.IsNullOrWhiteSpace(path))
                return string.Empty;
            if ((!string.IsNullOrWhiteSpace(rootPath)) && (!string.IsNullOrWhiteSpace(folderDelimiter)))
            {
                rootPath = rootPath.TrimEnd(folderDelimiter, System.StringComparison.OrdinalIgnoreCase);
                if (path.Equals(rootPath, System.StringComparison.OrdinalIgnoreCase))
                {
                    path = string.Empty;
                }
                else
                {
                    path = path.TrimStart(rootPath + folderDelimiter, System.StringComparison.OrdinalIgnoreCase);
                }
            }
            return path;
        }

        #endregion

        #endregion
    }
}
